package lion.dev.lang;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;

import lion.dev.web.Validator;

/**
 * Java Object Query Selector
 *
 * 对象选择语言，对对象内部字段进行查询
 *
 * /obj/b 选择某个字段
 * /obj/0 选择列表中第几个
 * /list/3/a list列表中第3个对象的a字段值
 * 过滤，对集合则进行逐个匹配，对对象则匹配字段
 * /obj/[k=v]
 * /obj/[k=v][k2=2]
 * /obj/[k=^a]
 * /obj/[k=a$]
 *
 *
 * @author helin
 * @email hl_0074@sina.com
 * @date 2017年1月12日
 */
public class Joqs {

	private static final Pattern pattern = Pattern.compile("\\[(.*?)\\]+");

	@SuppressWarnings("unchecked")
	public static <T> T select(String express, Object root) {

		if (root == null) { return null; }

		String[] nodes = StringUtils.split(express, "/");
		int i = 0;
		Object pnode = root;
		for (; i < nodes.length && pnode != null; i++) {
			String path = nodes[i];
			pnode = getNode(pnode, path);
			if (pnode == null) { return null; }
		}
		return (T) pnode;
	}

	/**
	 * @param pnode
	 * @param path
	 * @return
	 */
	private static Object getNode(Object pnode, String path) {

		Matcher matcher = pattern.matcher(path);
		if (!matcher.matches()) { return getValue(pnode, path); }

		// /a/b/[key=v][k1=v1]
		if (Collection.class.isAssignableFrom(pnode.getClass())) {// 如果是集合
			for (Object o : (Collection<?>) pnode) {
				if (matcheExpress(o, path)) { return o; }
			}
		} else {
			if (matcheExpress(pnode, path)) { return pnode; }
		}
		return null;
	}

	/**
	 * @param value
	 * @param pattern
	 * @return
	 */
	private static boolean matcheExpress(Object taget, String express) {

		if (taget == null) { return false; }

		Matcher matcher = pattern.matcher(express);
		while (matcher.find()) {
			String pair = matcher.group(1);
			String[] strs = pair.split("=");
			if (strs.length != 2) { return false; }

			String key = strs[0];
			String v = strs[1];

			if (!matchValue(getValue(taget, key), v)) { return false; }
		}

		return true;
	}

	/**
	 * @param v
	 * @param pattern
	 * @return
	 */
	private static boolean matchValue(Object value, String pattern) {

		if (value == null) { return false; }

		String v = value.toString();
		if (pattern.startsWith("^")) { return v.startsWith(pattern.substring(1)); }
		if (pattern.endsWith("$")) { return v.endsWith(pattern.substring(0, pattern.length() - 1)); }
		if (pattern.endsWith("~")) { return v.contains(pattern); }

		return StringUtils.equals(v, pattern);
	}

	/**
	 * @param obj
	 * @param field
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private static Object getValue(Object obj, String field) {

		// map类型
		if (Map.class.isAssignableFrom(obj.getClass())) { return ((Map<String, Object>) obj).get(field); }
		// 集合类型
		int i = Validator.toInt(field, -1);
		if (i > -1 && List.class.isAssignableFrom(obj.getClass())) {
			List<?> o = (List<?>) obj;
			if (i < o.size()) { return o.get(i); }
			return null;
		}

		// 数组类型
		if (i > -1 && obj.getClass().isArray() && Array.getLength(obj) > i) { return Array.get(obj, i); }

		// obj类型，读取字段
		BeanUtil beanUtil = new BeanUtil(obj);
		return beanUtil.getValue(field);
	}
}
